frontend/pages/e/[uuid].tsx (view raw)
1import {useState, useReducer, useEffect} from 'react';
2import {useTheme} from '@material-ui/core/styles';
3import {useTranslation} from 'react-i18next';
4import Joyride from 'react-joyride';
5import {initializeApollo} from '../../lib/apolloClient';
6import useToastStore from '../../stores/useToastStore';
7import useEventStore from '../../stores/useEventStore';
8import useTour from '../../hooks/useTour';
9import Layout from '../../layouts/Default';
10import AddToMyEventDialog from '../../containers/AddToMyEventDialog';
11import CarColumns from '../../containers/CarColumns';
12import NewCarDialog from '../../containers/NewCarDialog';
13import WelcomeDialog from '../../containers/WelcomeDialog';
14import EventBar from '../../containers/EventBar';
15import Loading from '../../containers/Loading';
16import Fab from '../../containers/Fab';
17import {
18 useUpdateEventMutation,
19 Event as EventType,
20 useEventByUuidQuery,
21 EventByUuidDocument,
22 EditEventInput,
23} from '../../generated/graphql';
24import ErrorPage from '../_error';
25
26const POLL_INTERVAL = 10000;
27
28interface Props {
29 event: EventType;
30 eventUUID: string;
31}
32
33const EventPage = props => {
34 const {t} = useTranslation();
35 const {event} = props;
36
37 if (!event) return <ErrorPage statusCode={404} title={t`event.not_found`} />;
38
39 return <Event {...props} />;
40};
41
42const Event = (props: Props) => {
43 const {eventUUID} = props;
44 const {t} = useTranslation();
45 const theme = useTheme();
46 const addToast = useToastStore(s => s.addToast);
47 const setEvent = useEventStore(s => s.setEvent);
48 const eventUpdate = useEventStore(s => s.event);
49 const setIsEditing = useEventStore(s => s.setIsEditing);
50 const [updateEvent] = useUpdateEventMutation();
51 const [isAddToMyEvent, setIsAddToMyEvent] = useState(false);
52 const [openNewCar, toggleNewCar] = useReducer(i => !i, false);
53 const {data: {eventByUUID: event} = {}} = useEventByUuidQuery({
54 pollInterval: POLL_INTERVAL,
55 variables: {uuid: eventUUID},
56 });
57 const {run, steps, step, onTourChange, onTourRestart} = useTour();
58
59 useEffect(() => {
60 if (event) setEvent(event as EventType);
61 }, [event]);
62
63 const onSave = async e => {
64 try {
65 const {uuid, ...data} = eventUpdate;
66 const {id, __typename, cars, users, waitingList, ...input} = data;
67 await updateEvent({
68 variables: {uuid, eventUpdate: input as EditEventInput},
69 refetchQueries: ['eventByUUID'],
70 });
71 setIsEditing(false);
72 } catch (error) {
73 console.error(error);
74 addToast(t('event.errors.cant_update'));
75 }
76 };
77
78 const onShare = async () => {
79 if (!event) return null;
80 // If navigator share capability
81 if (!!navigator.share)
82 return await navigator.share({
83 title: `Caroster ${event.name}`,
84 url: `${window.location.href}`,
85 });
86 // Else copy URL in clipboard
87 else if (!!navigator.clipboard) {
88 await navigator.clipboard.writeText(window.location.href);
89 addToast(t('event.actions.copied'));
90 return true;
91 }
92 };
93
94 if (!event) return <Loading />;
95
96 return (
97 <Layout
98 pageTitle={t('event.title', {title: event.name})}
99 menuTitle={t('event.title', {title: event.name})}
100 displayMenu={false}
101 >
102 <EventBar
103 event={event}
104 onAdd={setIsAddToMyEvent}
105 onSave={onSave}
106 onShare={onShare}
107 onTourRestart={onTourRestart}
108 />
109 <CarColumns toggleNewCar={toggleNewCar} />
110 <Fab open={openNewCar} onClick={toggleNewCar} aria-label="add-car" />
111 <NewCarDialog open={openNewCar} toggle={toggleNewCar} />
112 <AddToMyEventDialog
113 event={event}
114 open={isAddToMyEvent}
115 onClose={() => setIsAddToMyEvent(false)}
116 />
117 <WelcomeDialog />
118 <Joyride
119 run={run}
120 steps={steps}
121 stepIndex={step}
122 callback={onTourChange}
123 locale={t('joyride', {returnObjects: true})}
124 continuous={true}
125 showProgress={true}
126 disableScrolling={true}
127 disableScrollParentFix={true}
128 scrollToFirstStep={false}
129 floaterProps={{
130 disableAnimation: true,
131 }}
132 styles={{
133 options: {
134 primaryColor: theme.palette.primary.main,
135 },
136 tooltipContent: {
137 whiteSpace: 'pre-wrap',
138 },
139 }}
140 />
141 </Layout>
142 );
143};
144
145export async function getServerSideProps(ctx) {
146 const {uuid} = ctx.query;
147 const apolloClient = initializeApollo();
148 const {data = {}} = await apolloClient.query({
149 query: EventByUuidDocument,
150 variables: {uuid},
151 });
152 const {eventByUUID: event} = data;
153 const {host = ''} = ctx.req.headers;
154
155 return {
156 props: {
157 event,
158 eventUUID: uuid,
159 metas: {
160 title: event?.name || '',
161 url: `https://${host}${ctx.resolvedUrl}`,
162 },
163 },
164 };
165}
166
167export default EventPage;